using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Web.UI;
using DotNetNuke.Entities.Tabs;
using DotNetNuke.UI.Skins;

namespace HeroldIT.Dnn.SkinObjects
{
    /// <summary>
    /// The base for a SkinObject for generating breadcrumb related content.
    /// </summary>
    [DefaultProperty("Prefix")]
    public abstract class BreadcrumbBase : SkinObjectBase
    {
        #region static methods

        /// <summary>
        /// Gets the all instances of <see cref="BreadcrumbBase"/> controls on the page.
        /// </summary>
        /// <param name="page">The page to look on.</param>
        /// <returns>A list of <see cref="BreadcrumbBase"/> controls on the page, or <c>null</c> if none are present.</returns>
        public static IList<BreadcrumbBase> GetBreadcrumbBasesFor(Page page)
        {
            if (null == page)
                throw new ArgumentNullException("page");

            return page.Items[typeof(BreadcrumbBase)] as IList<BreadcrumbBase>;
        }

        #endregion

        #region properties

        private bool useTabName;

        /// <summary>
        /// Whether to use the TabName instead of Title for displaying. Default is <c>false</c>.
        /// </summary>
        [Browsable(true)]
        [Category("Behavior")]
        [DefaultValue(false)]
        [Localizable(false)]
        public bool UseTabName
        {
            get { return this.useTabName; }
            set { this.useTabName = value; }
        }

        private bool displayDisabled;

        /// <summary>
        /// Whether to display disabled parts of the breadcrumb in the title or just enabled parts. Default is <c>false</c>.
        /// </summary>
        [Browsable(true)]
        [Category("Behavior")]
        [DefaultValue(false)]
        [Localizable(false)]
        public bool DisplayDisabled
        {
            get { return this.displayDisabled; }
            set { this.displayDisabled = value; }
        }

        private PrefixType prefixType = PrefixType.HomeTabTitle;

        /// <summary>
        /// The source of the prefix for the title.
        /// </summary>
        [Browsable(true)]
        [Category("Behavior")]
        [DefaultValue(PrefixType.HomeTabTitle)]
        [Localizable(false)]
        public PrefixType PrefixType
        {
            get { return this.prefixType; }
            set { this.prefixType = value; }
        }

        private string prefix = String.Empty;

        /// <summary>
        /// The prefix to use.
        /// </summary>
        /// <remarks>
        /// This value will only be used, if <see cref="PrefixType"/> is set to <c><see cref="SkinObjects.PrefixType.CustomPrefix"/></c>.
        /// </remarks>
        [Browsable(true)]
        [Category("Behavior")]
        [DefaultValue("")]
        [Localizable(true)]
        public string Prefix
        {
            get { return this.prefix; }
            set { this.prefix = value; }
        }

        /// <summary>
        /// Whether to reverse the direction of the breadcrumb and use the prefix as a suffix. Default is <c>false</c>.
        /// </summary>
        [Browsable(true)]
        [Category("Behavior")]
        [DefaultValue(false)]
        [Localizable(true)]
        public bool ReverseDirection { get; set; }

        private string separator = " - ";

        /// <summary>
        /// The <see cref="String" /> to use for separating the different elements (prefix, breadcrumb parts).
        /// </summary>
        [Browsable(true)]
        [Category("Behavior")]
        [DefaultValue(" - ")]
        [Localizable(true)]
        public string Separator
        {
            get { return this.separator; }
            set { this.separator = value; }
        }

        /// <summary>
        /// Whether to use Apollo's PageLocalization framework.
        /// </summary>
        [Browsable(true)]
        [Category("Behavior")]
        [DefaultValue(false)]
        [Localizable(false)]
        public bool UsePageLocalization { get; set; }

        private TabController tabController;

        /// <summary>
        /// Gets an instance of a <see cref="DotNetNuke.Entities.Tabs.TabController"/>.
        /// </summary>
        protected TabController TabController
        {
            get
            {
                if (null == this.tabController)
                {
                    this.tabController = new TabController();
                }
                return this.tabController;
            }
        }

        private TabInfo homeTab;

        /// <summary>
        /// Gets the <see cref="TabInfo"/> of the portal's home tab.
        /// </summary>
        protected TabInfo HomeTab
        {
            get
            {
                if (null == this.homeTab)
                {
                    this.homeTab =
                        this.TabController.GetTab(this.PortalSettings.HomeTabId, this.PortalSettings.ActiveTab.PortalID,
                                                  false);
                    //if (this.UsePageLocalization)
                    //{
                    //    this.homeTab = LocalizeTab(this.homeTab);
                    //}
                }
                return this.homeTab;
            }
        }

        #endregion

        #region events

        /// <summary>
        /// Occurs when the control renders a breadcrumb part.
        /// </summary>
        public event EventHandler<BreadcrumbEventArgs> RenderingBreadcrumbPart;

        #endregion

        #region page lifecycle

        /// <summary>
        /// Raises the <see cref="E:System.Web.UI.Control.Init" /> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs" /> object that contains the event data.</param>
        protected override void OnInit(EventArgs e)
        {
            if (null != this.Page)
            {
                IList<BreadcrumbBase> breadcrumbs = GetBreadcrumbBasesFor(this.Page);
                if (null == breadcrumbs)
                {
                    this.Page.Items[typeof(BreadcrumbBase)] = new List<BreadcrumbBase> { this };
                }
                else
                {
                    breadcrumbs.Add(this);
                }
            }

            base.OnInit(e);
        }

        #endregion

        #region methods

        /// <summary>
        /// Gets the information for rendering the given <paramref name="tab"/>.
        /// </summary>
        /// <param name="tab">The tab for which to get the information for rendering.</param>
        /// <returns>The information for rendering the given <paramref name="tab"/>.</returns>
        protected BreadcrumbEventArgs GetRenderInfo(TabInfo tab)
        {
            var title = this.GetTabTitle(tab);
            BreadcrumbEventArgs e = new BreadcrumbEventArgs(tab.TabID, title, tab.FullUrl);
            this.OnRenderingBreadcrumbPart(e);
            if (String.IsNullOrEmpty(e.NameToRender))
            {
                e.NameToRender = title;
            }
            if (String.IsNullOrEmpty(e.UrlToRender))
            {
                e.UrlToRender = tab.FullUrl;
            }
            return e;
        }

        /// <summary>
        /// Gets the title for the tab based on the value of <see cref="UseTabName"/>.
        /// </summary>
        /// <param name="tab">The tab to get the title for.</param>
        /// <returns>The tab's title.</returns>
        protected string GetTabTitle(TabInfo tab)
        {
            return this.GetTabTitle(tab, false);
        }

        /// <summary>
        /// Gets the title for the tab based on the value of <see cref="UseTabName"/>.
        /// </summary>
        /// <param name="tab">The tab to get the title for.</param>
        /// <param name="forceTitle">Whether to force using the tab's title.</param>
        /// <returns>The tab's title.</returns>
        protected string GetTabTitle(TabInfo tab, bool forceTitle)
        {
            string title;

            if ((!this.useTabName || forceTitle) && !String.IsNullOrEmpty(tab.Title))
            {
                title = tab.Title;
            }
            else
            {
                title = tab.TabName;
            }
            return title;
        }

        /// <summary>
        /// Gets all breadcrumb parts that should be displayed. Any hidden items are left out.
        /// </summary>
        /// <returns>All breadcrumb parts that should be displayed.</returns>
        protected TabInfo[] GetBreadcrumbPartsToDisplay()
        {
            var parts = new List<TabInfo>();

            var tab = this.PortalSettings.ActiveTab;

            while (tab.ParentId >= 0)
            {
                tab = this.TabController.GetTab(tab.ParentId, tab.PortalID, false);
                if (this.UsePageLocalization)
                {
                    tab = Localizer.LocalizeTab(tab);
                }
                if (this.displayDisabled || tab.IsVisible)
                {
                    parts.Insert(0, tab);
                }
            }

            return parts.ToArray();
        }

        /// <summary>
        /// Gets the prefix text depending on the settings for <see cref="PrefixType"/> and <see cref="Prefix"/>.
        /// </summary>
        /// <returns>The prefix text.</returns>
        protected string GeneratePrefix()
        {
            switch (this.prefixType)
            {
                case PrefixType.CustomPrefix:
                    if (!String.IsNullOrEmpty(this.prefix))
                    {
                        return this.prefix;
                    }
                    break;

                case PrefixType.PortalName:
                    return this.PortalSettings.PortalName;

                case PrefixType.HomeTabName:
                    if (this.UsePageLocalization)
                    {
                        return Localizer.LocalizeTab(this.HomeTab).TabName;
                    }
                    return this.HomeTab.TabName;

                case PrefixType.HomeTabTitle:
                    if (this.UsePageLocalization)
                    {
                        return this.GetTabTitle(Localizer.LocalizeTab(this.HomeTab), true);
                    }
                    return this.GetTabTitle(this.HomeTab, true);

                case PrefixType.DomainName:
                    return this.Page.Request.Url.Host;
            }

            return null;
        }

        /// <summary>
        /// Raises the <see cref="RenderingBreadcrumbPart" /> event.
        /// </summary>
        /// <param name="e">A <see cref="BreadcrumbEventArgs" /> object that contains the event data.</param>
        protected void OnRenderingBreadcrumbPart(BreadcrumbEventArgs e)
        {
            if (null != this.RenderingBreadcrumbPart)
            {
                this.RenderingBreadcrumbPart(this, e);
            }
        }

        #endregion
    }
}